package com.stylefeng.guns.crawlers.zgzc;

import cn.wanghaomiao.seimi.def.BaseSeimiCrawler;
import com.google.common.collect.Lists;
import com.stylefeng.guns.common.persistence.dao.DictMapper;
import com.stylefeng.guns.common.persistence.dao.GameMapper;
import com.stylefeng.guns.common.persistence.model.Game;
import com.stylefeng.guns.common.persistence.model.History;
import com.stylefeng.guns.common.persistence.model.Lottery;
import com.stylefeng.guns.config.properties.HttpProxyProperties;
import com.stylefeng.guns.core.util.DigitalUtil;
import com.stylefeng.guns.modular.business.service.IGameService;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.seimicrawler.xpath.JXDocument;
import org.seimicrawler.xpath.JXNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
@Getter
public abstract class BaseZgcpCrawler extends BaseSeimiCrawler {


    /**
     * mid缓存key
     */
    public static final String CACHE_KEY = "mids";
    /**
     * 篮球mid缓存key
     */
    public static final String BS_CACHE_KEY = "bs_mids";

    public static final String ZGZCW = "http://cp.zgzcw.com/";
    // 分析
    public static final String FENGXI = "http://fenxi.zgzcw.com/";

    private static final List<String> COMPANY_NAMES = Arrays.asList("澳门", "立博", "Bet365", "威廉希尔");

    private static final long serialVersionUID = 7156963528823237584L;

    @Autowired
    protected transient IGameService gameService;

    @Autowired
    protected transient StringRedisTemplate stringRedisTemplate;

    @Resource(name = "jsonTemplate")
    protected transient RedisTemplate redisTemplate;

    @Autowired
    protected ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Autowired
    protected GameMapper gameMapper;

    @Autowired
    protected DictMapper dictMapper;

    @Autowired
    private HttpProxyProperties httpProxyProperties;

//    private String proxyIp = "39.135.9.97";
//    private int proxyPort = 8080;


    /**
     * 解析比赛历史数据
     *
     * @param game
     */
    public void parseAnalysis(Game game) {
        try {
            gameService.generateGame(game, getHistoryList(game), getLotteryList(game));
        } catch (Exception e) {
            log.warn("解析比赛id={}分析数据失败", game.getMid(), e);
        }
    }


    /**
     * 历史对阵记录
     *
     * @param game
     * @returns
     */
    public List<History> getHistoryList(Game game) throws IOException {

        Document document = processUrl(FENGXI + game.getMid() + "/bsls");
        JXDocument jxDocument = JXDocument.create(document);
        List<Object> compTypes = jxDocument.sel("//table[@class='tab-ls']/@id");
        // 轮次
        String lcStr = Optional.ofNullable(jxDocument.selOne("//div[@id='lc_head']/h2/@lc")).map(Object::toString).orElse("");
        try {
            int lc = Integer.parseInt(lcStr);
            game.setLc(lc);
        } catch (Exception ignored) {
            log.error("获取比赛的轮次数据失败,轮次信息为={}", lcStr);
        }
        Object matchTime = jxDocument.selOne("//div[@class='bfyc-duizhen-r']/div[@class='date']/span/text()");
        if (matchTime == null) {
            matchTime = jxDocument.selOne("//div[@class='bfyc-duizhen-r']/div[@class='date']/text()");
        }
        if (matchTime != null) {
            game.setTime(StringUtils.substringAfter(matchTime.toString(), "："));
        }

        List<History> histories = Lists.newArrayList();
        compTypes.stream().filter(object -> !"".equals(object)).forEach(object -> {
            String type = (String) object;
            List<Object> historyTrs = jxDocument.sel("//table[@id='" + type + "']/tbody/tr");
            int temp = 0;
            // 获取近六轮数据
            for (int i = 0; temp < 6 && i < historyTrs.size(); i++) {
                Element historyTr = (Element) historyTrs.get(i);
                List<Element> tds = historyTr.getElementsByTag("td");
                // 联赛名
                String title = tds.get(0).text();
                // 只爬联赛数据
                if (isLeague(title)) {
                    // 为1时队伍为客队，为0是队伍为主队
                    String flag = historyTr.attr("h");
                    // 对阵类型
                    String compType = getCompType(type);
                    // 比赛时间
                    String time = tds.get(2).text();
                    // 主队
                    String mainTeam = tds.get(3).getElementsByTag("a").text();
                    // 比分
                    String score = tds.get(4).getElementsByTag("a").text();
                    if (StringUtils.containsNone(score, ":")) {
                        continue;
                    }
                    String[] scores = StringUtils.split(score, ":");
                    // 客队
                    String otherTeam = tds.get(5).getElementsByTag("a").text();
                    // 总进球数
                    Integer goal = Arrays.stream(scores).mapToInt(Integer::valueOf).sum();

                    History history = new History();
                    history.setMid(game.getMid());
                    history.setTitle(title);
                    history.setTime(time);
                    history.setZhud(mainTeam);
                    history.setKeyd(otherTeam);
                    history.setGoal(goal);
                    history.setScore(score);
                    history.setCompType(compType);
                    history.setFlag(flag);
                    histories.add(history);
                    temp++;
                }
            }
        });
        return histories;
    }

    /**
     * 是否为联赛
     *
     * @param title
     * @return
     */
    public boolean isLeague(String title) {

        return !(StringUtils.contains(title, "杯") || StringUtils.contains(title, "友谊")
                || StringUtils.contains(title, "亚冠") || StringUtils.contains(title, "欧冠")
                || StringUtils.contains(title, "足总") || StringUtils.contains(title, "亚运")
                || StringUtils.contains(title, "奥运") || StringUtils.contains(title, "赛")
                || StringUtils.contains(title, "欧国联"));
    }


    /**
     * 获得已经爬取的比赛记录
     *
     * @return
     */
    public List<String> getMids() {
//        long size = stringRedisTemplate.opsForList().size(cachekey);
        List<String> cacheMids;
//        if (size > 0) {
//            cacheMids = stringRedisTemplate.opsForList().range(cachekey, 0, size - 1);
//        } else {
        cacheMids = gameMapper.findMid();
//            if (!cacheMids.isEmpty()) {
//                stringRedisTemplate.opsForList().leftPushAll(cachekey, cacheMids);
//            }
//        }
        return cacheMids;
    }

    /**
     * 解析大小对比，亚盘，欧赔等数据
     *
     * @param game
     */
    public List<Lottery> getLotteryList(Game game) throws IOException {

        String urlPrefix = FENGXI + game.getMid();
        List<Lottery> dxdb = getDxdb(urlPrefix);
        List<Lottery> ypdb = getYpdb(urlPrefix);
        List<Lottery> bjop = getBjop(urlPrefix);

        Map<String, Lottery> dxdbMap = dxdb.stream().collect(Collectors.toMap(Lottery::getCompany, x -> x));
        Map<String, Lottery> ypdbMap = ypdb.stream().collect(Collectors.toMap(Lottery::getCompany, x -> x));
        Map<String, Lottery> bjopMap = bjop.stream().collect(Collectors.toMap(Lottery::getCompany, x -> x));

        return COMPANY_NAMES.stream().map(x -> {
            Lottery lottery = new Lottery();
            lottery.setMid(game.getMid());

            Lottery lottery1 = dxdbMap.get(x);
            Lottery lottery2 = ypdbMap.get(x);
            Lottery lottery3 = bjopMap.get(x);

            if (lottery1 != null) {
                lottery.setCompany(lottery1.getCompany());
                lottery.setCompanyId(lottery1.getCompanyId());
                lottery.setDxHandicap(lottery1.getDxHandicap());
                lottery.setBigOdds(lottery1.getBigOdds());
                lottery.setSmallOdds(lottery1.getSmallOdds());
                lottery.setPfl(lottery1.getPfl());
            }
            if (lottery2 != null) {
                lottery.setCompany(lottery2.getCompany());
                lottery.setAsianHandicap(lottery2.getAsianHandicap());
                lottery.setzOdds(lottery2.getzOdds());
                lottery.setkOdds(lottery2.getkOdds());
            }
            if (lottery3 != null) {
                lottery.setCompany(lottery3.getCompany());
                lottery.setWinOdds(lottery3.getWinOdds());
                lottery.setDrawOdds(lottery3.getDrawOdds());
                lottery.setLossOdds(lottery3.getLossOdds());
            }
            return lottery;

        }).filter(x -> StringUtils.isNotEmpty(x.getCompany())).collect(Collectors.toList());
    }


    /**
     * @param urlPrefix
     * @return
     */
    private List<Lottery> getBjop(String urlPrefix) throws IOException {

        log.info("获取百家欧赔数据");
        List<Lottery> lotteries = Lists.newArrayList();
        Document document = processUrl(urlPrefix + "/bjop");
        JXDocument jxDocument = JXDocument.create(document);
        List<Object> companyTrs = jxDocument.sel("//div[@id='data-body']/table/tbody/tr");
        for (Object tr : companyTrs) {
            Lottery lottery = null;
            Element element = (Element) tr;
            List<Element> tds = element.getElementsByTag("td");
            // 公司名称
            String company = tds.get(1).text();
            String companyId = tds.get(5).attr("cid");
            if (COMPANY_NAMES.contains(company)) {
                lottery = new Lottery();
                // 胜
                String wOdds = tds.get(2).text();
                // 平
                String dOdds = tds.get(3).text();
                // 服
                String lOdds = tds.get(4).text();

                log.info("{}，{}，{}", wOdds, dOdds, lOdds);

                lottery.setCompany(company);
                lottery.setCompanyId(companyId);
                lottery.setWinOdds(Double.parseDouble(wOdds));
                lottery.setDrawOdds(Double.parseDouble(dOdds));
                lottery.setLossOdds(Double.parseDouble(lOdds));
                lotteries.add(lottery);
            }

        }
        return lotteries;
    }

    /**
     * 亚盘对比数据
     *
     * @param urlPrefix
     * @return
     */
    private List<Lottery> getYpdb(String urlPrefix) throws IOException {

        Document document = processUrl(urlPrefix + "/ypdb");
        JXDocument jxDocument = JXDocument.create(document);
        List<Object> companyTrs = jxDocument.sel("//div[@id='data-body']/table/tbody/tr");
        return companyTrs.stream().map(tr -> {
            Lottery lottery = null;
            Element element = (Element) tr;
            List<Element> tds = element.getElementsByTag("td");
            // 公司名称
            String company = tds.get(1).text();
            String companyId = tds.get(5).attr("cid");
            if (COMPANY_NAMES.contains(company)) {
                lottery = new Lottery();

                // 亚盘盘口
                String handicap = tds.get(3).text();
                double asianHandicap = DigitalUtil.getDigitalFromHandicap(handicap);
                // 立博大球赔率
                String zOdds = tds.get(2).text();
                // 立博小球赔率
                String kOdds = tds.get(4).text();

                lottery.setCompany(company);
                lottery.setCompanyId(companyId);
                lottery.setzOdds(Double.parseDouble(zOdds));
                lottery.setkOdds(Double.parseDouble(kOdds));
                lottery.setAsianHandicap(asianHandicap);
            }
            return lottery;
        }).filter(Objects::nonNull).collect(Collectors.toList());

    }

    /**
     * 大小对比数据
     *
     * @param urlPrefix
     * @return
     */
    private List<Lottery> getDxdb(String urlPrefix) throws IOException {
        Document document = processUrl(urlPrefix + "/dxdb");
        JXDocument jxDocument = JXDocument.create(document);
        List<Object> companyTrs = jxDocument.sel("//div[@id='data-body']/table/tbody/tr");
        return companyTrs.stream().map(tr -> {
            Lottery lottery = null;
            Element element = (Element) tr;
            List<Element> tds = element.getElementsByTag("td");
            // 公司名称
            String company = tds.get(1).text();
            String companyId = tds.get(5).attr("cid");
            if (COMPANY_NAMES.contains(company)) {
                lottery = new Lottery();
                // 大小球盘口
                String handicap = tds.get(3).text();
                handicap = StringUtils.removeEndIgnoreCase(handicap, "球");
                if (handicap.contains("/")) {
                    String[] strings = StringUtils.split(handicap, "/");
                    handicap = String.valueOf((Double.parseDouble(strings[0]) + Double.parseDouble(strings[1])) / 2);
                }
                // 大球赔率
                String bOdds = tds.get(2).text();
                // 小球赔率
                String sOdds = tds.get(4).text();
                // 赔付率
                String pflUrl = tds.get(5).getElementsByTag("a").attr("href");
                double pfl = 0;
                try {
                    pfl = getPfl(pflUrl);
                } catch (IOException e) {
                    log.error("获取赔付率失败");
                }

                lottery.setCompany(company);
                lottery.setCompanyId(companyId);
                lottery.setBigOdds(Double.parseDouble(bOdds));
                lottery.setSmallOdds(Double.parseDouble(sOdds));
                lottery.setDxHandicap(Double.parseDouble(handicap));
                lottery.setPfl(pfl);
            }
            return lottery;
        }).filter(Objects::nonNull).collect(Collectors.toList());
    }


    private String getCompType(String type) {
        if (StringUtils.equals(type, "match_Home")) {
            return "homecomp";
        } else if (StringUtils.equals(type, "match_Guest")) {
            return "awaycomp";
        } else if (StringUtils.equals(type, "match_His")) {
            return "vscomp";
        }
        return null;
    }

    /**
     * 获取赔付率
     *
     * @param pflUrl
     * @return
     */
    protected double getPfl(String pflUrl) throws IOException {

        String url = StringUtils.substringBeforeLast(FENGXI, "/") + pflUrl;
        Document document = processUrl(url);
        List<JXNode> trs = JXDocument.create(document).selN("//tr");
        if (!CollectionUtils.isEmpty(trs)) {
            String pfl = trs.get(trs.size() - 1).asElement().getElementsByTag("td").get(10).text();
            return Double.parseDouble(pfl);
        }
        return 0d;
    }


    /**
     * 请求url
     *
     * @param url
     * @return
     */
    protected Document processUrl(String url) throws IOException {


        // 创建代理服务器地址对象
        InetSocketAddress addr = new InetSocketAddress(httpProxyProperties.getServer(), httpProxyProperties.getPort());
        // 创建HTTP类型代理对象
        Proxy proxy = new Proxy(Proxy.Type.HTTP, addr);

        return Jsoup.connect(url).header("Proxy-Authorization", "Basic " + httpProxyProperties.getAppSecret())
                .timeout(5000)
                .proxy(proxy)
                .ignoreContentType(true)
                .userAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36")
                .header("referer", "http://cp.zgzcw.com/lottery/bdplayvsforJsp.action?lotteryId=200&v=1224")
                .get();

    }

}
